-- AlchemyWorkshopM
-- created by zouyb
-- 炼金工坊模块

require "game/logic/module/TimeM"

module("AlchemyWorkshopM", package.seeall);

local workshopItems = {};
local workshopGuideConfig = {};
local workshopStrengthenCost = {};

local maxGuideId = 0;

-- 工坊信息
local workshopInfo = nil;

-- 强化信息
local workshopStrengthen = {};

-- 引导进度信息
local workshopGuideProgress = {};

-- 离线产出信息
local offlineBonus = {};

-- 强化项提醒信息
local workshopStrengthenRemindTable = {};

local startTime = TimeM.getCurrentTime();

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    local workshop_item_CSV = get_workshop_item_CSV();

    workshopItems = {};
    for i = 1, #workshop_item_CSV do
        local id = workshop_item_CSV[i].id;
        workshopItems[id] = parseDesc(workshop_item_CSV[i]);
    end

    workshopGuideConfig = {};
    local workshop_guide_CSV = get_workshop_guide_CSV();
    for i = 1, #workshop_guide_CSV do
        local id = workshop_guide_CSV[i].id;
        workshopGuideConfig[id] = workshop_guide_CSV[i];

        if id > maxGuideId then
            maxGuideId = id
        end
    end

    workshopStrengthenCost = {};
    local workshop_strengthen_cost_CSV = get_workshop_strengthen_cost_CSV();
    for _, info in pairs(workshop_strengthen_cost_CSV) do
        local id = info.id;
        workshopStrengthenCost[id] = info;
    end
end

-- 模块初始化操作
function init()
    -- 重置所有数据
    clearData();

    loadCsv();
end

-- 清除旧数据
function clearData()
    workshopInfo = nil;
    workshopStrengthen = {};
    workshopGuideProgress = {};
    offlineBonus = {};
    workshopStrengthenRemindTable = {};
    startTime = TimeM.getCurrentTime();
end

-- 解析描述
function parseDesc(info)
    local str = info["strengthen_desc"];
    if str ~= nil and str ~= "" then
        local descList = string.explode(str, "|");
        info["strengthen_desc"] = descList;
    end
    return info;
end

-- 获取强化描述
function getStrengthenDesc(id, level)
    if level == 0 then
        return query(id, "desc");
    else
        local descList = query(id, "strengthen_desc");
        local desc;
        if type(descList) == "table" then
            desc = descList[level];
            if desc == nil then
                desc = descList[1];
            end
        else
            print(descList);
            desc = descList;
        end

        return desc;
    end
end

-- 检索信息
function query(id, path)
    local m = workshopItems[id];
    if m == nil then
        return nil;
    end
    if (path == "" or path == nil) then
        return m;
    else
        return m[path];
    end
end

-- 检索引导信息
function queryGuideConfig(id, path)
    local m = workshopGuideConfig[id];
    if m == nil then
        return nil;
    end
    if (path == "" or path == nil) then
        return m;
    else
        return m[path];
    end
end

-- 获取所有引导列表
function getGuideConfig()
    return workshopGuideConfig;
end

-------------------------------------
-- 增加工人数量
-- @function [#parent=AlchemyWorkshopM] addWorkerNum
-- @param workshopType 工坊类型
-- @param amount 数量
function addWorkerNum(workshopType, amount)
    Operation.cmd_add_worker_num(workshopType, amount);
end

-------------------------------------
-- 减少工人数量
-- @function [#parent=AlchemyWorkshopM] subWorkerNum
-- @param workshopType 工坊类型
-- @param amount 数量
function subWorkerNum(workshopType, amount)
    Operation.cmd_sub_worker_num(workshopType, amount);
end

-------------------------------------
-- 响应炼金事件
-- @function [#parent=AlchemyWorkshopM] responseEvent
-- @param result 响应结果 0 表示拒绝  1 表示同意
function responseEvent(result)
    Operation.cmd_response_event(result);
end

-- 更新工坊信息
function updateWorkshop(workshop)
    workshopInfo = workshop;

    -- 记录空闲冈布奥学徒数量
    ME.user.dbase:set("idle_worker_num", workshop["idle"]);

    -- 记录已购买学徒数量
    ME.user.dbase:set("has_buy_worker_num", workshop["has_buy_worker_num"]);

    EventMgr.fire(event.WORKSHOP_INFO_UPDATED);
end

-- 获取工坊信息
function getWorkshop()
    return workshopInfo;
end

-- 获取已购买工人的数目
function getHasBuyWorkerNum()
    return ME.user:queryAttrib("has_buy_worker_num");
end

-- 本地预先增加已购买的学徒数量
function preAddBuyWorkerNum(num)
    ME.user:addAttrib("has_buy_worker_num", num)
end

-- 获取工人总数
function getTotalWorkerNum()
    if workshopInfo == nil then
        return 0;
    end

    local total = 0;
    for i = 1, 9 do
        total = total + workshopInfo[i];
    end

    return total + getIdleWorkerNum();
end

-- 获取空闲工人数
function getIdleWorkerNum()
    return ME.user:queryAttrib("idle_worker_num");
end

-- 最大离线奖励时间
function calcMaxOffline()
    -- 等级
    local currLevel = ME.user.dbase:query("level", 1);

    -- 最大累计时间
    local offlineLimit = UserM.queryWorldTree(currLevel, "offline_produce_time");
    local prop = PropM.combine(ME.user, "alchemist_time", 1);
    offlineLimit = PropM.apply(prop, offlineLimit);

    -- 月卡加成
    offlineLimit = offlineLimit + (SuperiorM.getSuperiorPrivilege("workshop") or 0);

    return offlineLimit;
end

-- 累加产出信息
function saveBonus(bonus)
    if offlineBonus["product"] == nil then
        offlineBonus["product"] = {};
    end

    local productList = bonus["product"];
    if #productList <= 0 then
        return;
    end

    local index = 1;
    for _, product in pairs(productList) do
        if product["src"] and product["src"][2] == "money" then
            -- 检测金币是否到达采集上限
            AlchemyWorkshopM.checkMoneyLimit();
            -- 奖励金币
            BonusM.doBonus(product["src"], "workshopBonus");
        elseif product["src"] and product["src"][1] == 1 then
            -- 奖励物品
            ItemM.updateItem(ME.user,  product["src"][2], ItemM.getAmount(ME.user, product["src"][2]) + product["src"][3]);
            -- 扣除合成消耗
            if product["cos"] and product["cos"][2] > 0 then
                ItemM.updateItem(ME.user,  product["cos"][1], ItemM.getAmount(ME.user, product["cos"][1]) - product["cos"][2]);
            end
        end

        -- 收到了自动合成的结果，由于服务器不下发，客户端自己添加下合成的道具数量
        if product["dst"] and product["dst"][3] > 0 then
            ItemM.addAmount(ME.user, product["dst"][2], product["dst"][3]);
        end

        local find = false;
        for _, alProduct in pairs(offlineBonus["product"]) do
            if product["src"] then
                if alProduct["src"] then
                    if product["src"][1] == alProduct["src"][1] and product["src"][2] == alProduct["src"][2] then
                        alProduct["src"][3] = alProduct["src"][3] + product["src"][3];
                        find = true;
                    end
                end
            end
            if product["dst"] then
                if alProduct["dst"] then
                    if product["dst"][1] == alProduct["dst"][1] and product["dst"][2] == alProduct["dst"][2] then
                        alProduct["dst"][3] = alProduct["dst"][3] + product["dst"][3];
                        find = true;
                    end
                else
                    if find then
                        alProduct["dst"] = product["dst"];
                    end
                end

            end
            if find then
                break;
            end
        end
        if false == find then
            table.insert(offlineBonus["product"], productList[index]);
--            offlineBonus["product"] = table.insert(offlineBonus["product"], productList[index]);
        end
        index = index + 1;
    end

--    offlineBonus["product"] = productList;
end

-- 对产物进行排序
local function sortBonus(product1, product2)
    local classId1 = tonumber(product1["src"][2]);
    local classId2 = tonumber(product2["src"][2]);
    classId1 = iif(classId1 == nil, 0, classId1);
    classId2 = iif(classId2 == nil, 0, classId2);

    -- 根据classId升序
    if classId1 < classId2 then
        return true;
    else
        return false;
    end
end

-- 获取离线产出信息
function fetchBonusText()
    local bonus = offlineBonus;

    if bonus["product"] == nil then
        return "";
    end

    local productList = bonus["product"];

    -- 对产物进行排序
    table.sort(productList, sortBonus);

    local text = getLocStr("workshop_bonus1");
    for _, product in pairs(productList) do
        local srcId  = product["src"][2];
        local srcNum = product["src"][3];
        local srcName = "";
        if product["src"][1] == 1 then
            -- 物品
            srcName = ItemM.query(srcId, "name");
        elseif product["src"][1] == 2 then
            -- 属性
            srcName = FieldsM.getFieldName(srcId);
        else
        -- 暂不处理
        end

        local str =  "[blue]" .. srcName .. " " .. srcNum .. "[-] ";
        text = text .. str;

        -- 如果有合成产物
        -- 非中文版本就不要显示合成获得信息了
        if product["dst"] ~= nil and
           (getLang() == "zh" or getLang() == "tw") then
            local dstId  = product["dst"][2];
            local dstNum = product["dst"][3];
            local dstName = "";
            if product["dst"][1] == 1 then
                -- 物品
                dstName = ItemM.query(dstId, "name");

                -- 自动合成的提示
                text = text .. string.format(getLocStr("workshop_bonus2"), dstNum, dstName) .. "\n";
            else
                text = text .. "\n";
            end
        else
            text = text .. "\n";
        end
    end

    -- 获取后即可删除，防止重复提取
    offlineBonus = {};
    return text, #productList;
end

-- 生成简短的产出信息
function genBriefText()
    local bonus = offlineBonus;

    if bonus["product"] == nil then
        return "";
    end

    local productList = bonus["product"];

    table.sort(productList, sortBonus);

    local textList = {};
    local count = 1;
    for _, product in pairs(productList) do
        local srcId  = product["src"][2];
        local srcNum = product["src"][3];
        local srcName = "";
        if product["src"][1] == 1 then
            -- 物品
            srcName = ItemM.query(srcId, "name");
        elseif product["src"][1] == 2 then
            -- 属性
            srcName = FieldsM.getFieldName(srcId);
        else
        -- 暂不处理
        end

        local str = string.format(getLocStr("item_bonus_format2"), srcName, srcNum);
        table.insert(textList, str);

        -- 如果有合成产物
        if product["dst"] ~= nil then
            local dstId  = product["dst"][2];
            local dstNum = product["dst"][3];
            local dstName = "";
            if product["dst"][1] == 1 then
                -- 物品
                dstName = ItemM.query(dstId, "name");
            elseif product["dst"][1] == 2 then
                -- 属性
                dstName = FieldsM.getFieldName(dstId);
            else
            -- 暂不处理
            end

            -- 自动合成的提示
            if dstNum > 0 then
                local str = string.format(getLocStr("item_bonus_format2"), dstName, dstNum);
                table.insert(textList, str);
            end
        end
    end

    -- 获取后即可删除，防止重复提取
    offlineBonus = {};
    return textList;
end


-- 获取开始时间
function getStartTime()
    return startTime;
end

-- 重设开始时间（UIMainMap里调用）
function setStartTime(setTime)
    startTime = setTime;
end

-- 更新炼金熔炉信息
function updateWorkshopStrengthenInfo(info)
    workshopStrengthen = info;
    if ME.isInGame then
        PropM.refreshEffect(ME.user, "workshop");
    end

    EventMgr.fire(event.WS_STRENGTHEN_INFO);
end

-- 获取强化列表
function getStrengthenList()
    -- 为了防止外面修改掉数值，这里deepcopy一下
    return table.deepcopy(workshopStrengthen);
end

-- 是否有可强化的熔炉物品
function readyForStrengthen()
    for _, info in pairs(workshopStrengthen) do
        local id = info.id;
        local level = info.level or 0;
        if needShowBubble(id, level) == true then
            return true;
        end
    end

    return false;
end

-- 是否显示泡泡
function needShowBubble(id, level)
    return canStrengthen(id) == true and not isStrengthenItemReminded(id, level);
end

-- 熔炉物品是否已解锁
function isItemUnlock(id)
    for tempId, info in pairs(workshopStrengthen) do
        if tonumber(tempId) == id then
            return true;
        end
    end

    return false;
end

-- 获取熔炉强化等级
function getStrengthenLevel(id)
    for tempId, info in pairs(workshopStrengthen) do
        if tonumber(tempId) == id then
            return info.level or 0;
        end
    end

    return 0;
end

-- 获取熔炉消耗
function getStrengthenCost(id, level)
    local path = "level" .. level;
    local cost = workshopStrengthenCost[id][path];
    if cost == nil or type(cost) ~= "table" then
        return {};
    end

    return cost;
end

-- 获取强化项是否已经提醒过
function isStrengthenItemReminded(id, level)
    -- 有几个例外的
    local ret = FormulaM.invoke("IS_STRENGTHEN_REMIND_EXCEPTION", id, level);
    if ret then
        -- 需要一直提醒
        return false;
    end

    -- 获取当前的提醒情况
    if workshopStrengthenRemindTable[id] == nil or workshopStrengthenRemindTable[id][level] == nil then
        return false;
    end

    return true;
end

-- 获取强化项是否已经提醒过
function setStrengthenItemReminded(id, level)
    if workshopStrengthenRemindTable[id] == nil then
        workshopStrengthenRemindTable[id]  = {};
    end

    workshopStrengthenRemindTable[id][level] = 1;
end

-- 熔炉物品是否可以强化
function canStrengthen(id)
    local maxTimes = query(id, "max_strengthen_times") or 0;
    local times = getStrengthenLevel(id);

    -- 如果配置了公式，那么调用公式计算最大次数
    local prefix = "formula_";
    if type(maxTimes) == "string" and
        string.startWith(maxTimes, "formula_") then
        local formulaName = string.sub(maxTimes, string.len(prefix) + 1);
        maxTimes = FormulaM.invoke(formulaName);
    end

    if times >= maxTimes then
        return "max_times";
    end

    -- 判断限制条件是否满足
    local strenghtenFormulaName = query(id, "strengthen_formula");
    if strenghtenFormulaName ~= nil and strenghtenFormulaName ~= "" then
        local ret = FormulaM.invoke(strenghtenFormulaName, ME.user, id);
        if ret ~= true  then
            return ret;
        end
    end

    -- 判断消耗是否满足
    local cost = getStrengthenCost(id, times + 1);
    for _, arr in pairs(cost) do
        if arr[1] == 1 then
            if ItemM.getAmount(ME.user, arr[2]) < arr[3] then
                return "not_enough_item_to_strengthen";
            end
        elseif arr[1] == 2 then
            if ME.user:queryAttrib(arr[2]) < arr[3] then
                if arr[2] == "money" then
                    return "not_enough_money_to_strengthen", arr[3];
                elseif arr[2] == "gem" then
                    return "not_enough_gem_to_strengthen";
                end
            end
        end
    end

    return true;
end

-- 获得熔炉相关的属性提升
function fetchProps()
    local props = {}

    for id, info in pairs(workshopStrengthen) do
        local id = tonumber(id);

        local level = getStrengthenLevel(id);
        local addValue = query(id, "add_value");

        local tempProps = query(id, "prop");

        if tempProps then
            for _, prop in pairs(tempProps) do
                if #prop > 0 then
                    local p = table.copy(prop);
                    p[3] = level*addValue;
                    props = table.append(props, { p });
                end
            end
        end
    end

    return props;
end

-- 更新炼金熔炉引导进度信息
function updateWorkshopGuideProgress(info)
    workshopGuideProgress = info;
end

-- 获取引导进度信息
function getNextWorkshopGuideId()
    if workshopGuideProgress == nil then
        return 1;
    end

    local maxId = 0;
    for tempId, _ in pairs(workshopGuideProgress) do
        if tempId > maxId then
            maxId =  tempId;
        end
    end

    if workshopGuideConfig[maxId + 1] == nil then
        return nil;
    end

    return maxId + 1;
end

-- 是否已经引导过
function isGuideFinished(id)
    if SKIP_WORKSHOP_GUIDE == 1 then
        return true;
    end

    if workshopGuideProgress[id] == 1 then
        return true;
    end

    return false;
end

-- 是否所有引导都已完毕
function isAllGuideFinished()
    return isGuideFinished(maxGuideId);
end

-- 是否需要显示炼金坊界面
function needShowWorkshopForm()
    -- 第8步引导没完成时才显示
    if not AlchemyWorkshopM.isAllGuideFinished() and not isGuideFinished(8) then
        return true;
    end

    return false;
end

-- 检测属性是否达到最大值
function checkMoneyLimit()
    -- 还没登录到游戏中，不应该发的
    if not ME.isInGame then
        return;
    end

    local curValue = ME.user.dbase:query("money", 0);
    -- 金币采集上限
    local maxValue = FormulaM.invoke("CALC_USER_MAX_MONEY", ME.user);

    if curValue >= maxValue then
        -- 如果没提示过，则提示一次
        if not ME.user.dbase:query("max_money_tip") then
            ME.user.dbase:set("max_money_tip", true);
            alert(getLocStr("money_limit_tip"));
        end
    end
end

-- 强化斥候探索
function strengthenScout()
    local addValue = query(17, "add_value");
    local value = ME.user.dbase:query("scout") or 0;

    value = value + addValue;
    ME.user.dbase:set("scout", value);
end

-- 强化
function strengthenWorkshopItem(id)
    local times = getStrengthenLevel(id);
    local info = workshopStrengthen[tostring(id)];

    if not info then
        return false;
    end

    -- 判断消耗是否满足
    local cost = getStrengthenCost(id, times + 1);
    for _, arr in pairs(cost) do
        if arr[1] == 1 then
            ItemM.costAmount(ME.user, arr[2], arr[3]);
        elseif arr[1] == 2 then
            ME.user:costAttrib(arr[2], arr[3]);
        end
    end

    -- 客户端先升级
    info["level"] = (info["level"] or 0) + 1;
    info["times"] = (info["times"] or 0) + 1;

    return true;
end
